package com.js.lib.mybitsplus;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.js.lib.annotation.ApiLogger;
import com.js.lib.mybitsplus.page.JsPage;
import com.js.lib.mybitsplus.page.ResultPage;
import com.js.lib.result.ApiResult;
import com.js.lib.result.Result;
import com.js.lib.validator.ValidList;
import com.js.lib.validator.group.IAdd;
import com.js.lib.validator.group.ISelect;
import com.js.lib.validator.group.IUpdate;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import java.lang.reflect.Constructor;
import java.util.List;

/**
 * 新的 Controller 通用接口类
 * @param <T>  实体类，对应数据库表
 * @param <I>  结果类，如通过多表联合查询的得到的结果集
 * @param <P>  参数类，查询时使用的参数类，比如时间字段，查询可能会有开始时间，结束时间
 * @param <Service> 业务实现接口类
 * @param <W> Wrapper类，生成WHERE 语句的规则
 */
@Slf4j
public abstract class JsController<T,I,P,Service extends IJsService<T,I,P>,W extends JsWrapper<P>> {
    @Autowired(required = false)
    protected Service baseService;

    /** 通过反射 获得 Wrapper类 和 P类 */
    protected Class<W> wrapperClass = (Class<W>) ReflectionKit.getSuperClassGenericType(getClass(), 4);
    protected Class<P> paramClass = (Class<P>) ReflectionKit.getSuperClassGenericType(getClass(), 2);

    /**
     * 批量新增
     */
    @ApiLogger(apiName="/adds")
    @ApiOperation(value = "批量新增")
    @PostMapping("/adds")
    @ResponseBody
    public ApiResult<T>  adds(@Validated(IAdd.class) @RequestBody ValidList<T> datas) {
        baseService.saveBatch(datas,datas.size());
        return (ApiResult<T>) ApiResult.ok(String.valueOf(datas.size()));
    }

    /**
     * 新增
     * id=null
     * @param data
     * @return
     */
    @ApiLogger(apiName="/add")
    @ApiOperation(value = "新增")
    @PostMapping("/add")
    @ResponseBody
    public ApiResult<T> add(@Validated(IAdd.class) @RequestBody T data) {
        baseService.save(data);
        return (ApiResult<T>) ApiResult.ok(data);
    }

    /**
     * 修改，只修改属性不为空的字段
     * id != null
     * @param data
     * @return
     */
    @ApiLogger(apiName="/update")
    @ApiOperation(value = "修改(为空的参数不更新)")
    @PostMapping("/update")
    @ResponseBody
    public ApiResult<T> update(@Validated(IUpdate.class) @RequestBody T data) {
        baseService.updateById(data);
        return (ApiResult<T>) ApiResult.ok();
    }

    /**
     * 删除
     */
    @ApiLogger(apiName="/delete/{id}")
    @ApiImplicitParams({
            @ApiImplicitParam(name="id", value = "项目ID)", dataTypeClass = Long.class)
    })
    @ApiOperation(value = "删除")
    @PostMapping("/delete/{id}")
    @ResponseBody
    public Result delete(@PathVariable Long id) {

        baseService.removeById(id);
        return Result.ok();
    }

    /**
     * 查询所有数据
     * 结果类为 I
     * @return
     */
    @ApiLogger(apiName="/query/list")
    //@GetMapping("/query/list")
    @PostMapping("/query/list")
    @ApiOperation(value = "查询所有")
    @ResponseBody
    public ApiResult<I> queryList() {
        List<I> datas = baseService.listInfo();
        return (ApiResult<I>) ApiResult.ok(datas);
    }
    /**
     * 按条件查询一个
     * 参数类 P
     * 结果类 I
     * @param p
     * @return
     */
    @ApiOperation(value = "按条件查询一个")
    @PostMapping("/query/one")
    @ResponseBody
    public ApiResult<I> getOne(@Validated(ISelect.class) @RequestBody P p) {
        I data = baseService.getOneInfo(getNewWrapper(p),false);
        if (data == null){
            return (ApiResult<I>) ApiResult.ok("没有符合条件的数据");
        }else{
            return (ApiResult<I>) ApiResult.ok(data);
        }

    }


    /**
     * 按条件查询
     * 参数类 P
     * 结果类 I
     * @param p
     * @return
     */
    @ApiOperation(value = "按条件查询")
    @PostMapping("/query/wherelist")
    @ResponseBody
    public ApiResult<I> queryExtenWhereList(@Validated(ISelect.class) @RequestBody P p) {
        List<I> datas = baseService.listInfo(getNewWrapper(p));
        return (ApiResult<I>) ApiResult.ok(datas);
    }

    /**
     * 按条件分页查询
     * 参数类 P
     * 结果类 I
     * @param page
     * @return
     */
    @ApiOperation(value = "按条件分页查询")
    @PostMapping("/query/page")
    @ResponseBody
    public ApiResult<ResultPage<I>> queryExtenPage(@Validated(IPage.class) @RequestBody JsPage<P> page) {
        Page<P> page1 = new Page<>();
        page1.setSize(page.getPage().getSize());
        page1.setCurrent(page.getPage().getCurrent());
        if (page.getPage().getAscs()!=null && page.getPage().getAscs().length>0){
            page1.addOrder(OrderItem.ascs(page.getPage().getAscs()));
        }
        if (page.getPage().getDesc()!=null && page.getPage().getDesc().length>0){
            page1.addOrder(OrderItem.ascs(page.getPage().getDesc()));
        }

        Page<I> page2 = baseService.pageInfo(page1, getNewWrapper(page.getWhere()));
        ResultPage<I> resultPage =  new ResultPage<I>();
        resultPage.setPageSize(page2.getSize());
        resultPage.setCurrentPage(page2.getCurrent());
        resultPage.setTotal(page2.getTotal());
        resultPage.setRows(page2.getRecords());
        return (ApiResult<ResultPage<I>>) ApiResult.ok(resultPage);
    }

    /**
     * 生成查询条件的 Wrapper
     * @param p
     * @return
     */
    protected W getNewWrapper(P p) {
        try{
            /** 带参数的反射构造 */
            Constructor<W> c=wrapperClass.getConstructor(paramClass);//获取有参构造
            W w= c.newInstance(p);
            return w;
        }catch (InstantiationException e1){
            log.error(">>>>>>>InstantiationException: {}",e1);
        }catch (IllegalAccessException e2){
            log.error(">>>>>>>IllegalAccessException: {}",e2);
        }catch (NoSuchMethodException e3){
            log.error(">>>>>>>NoSuchMethodException: {}",e3);
        }catch (SecurityException e4){
            log.error(">>>>>>>SecurityException: {}",e4);
        }catch (Exception e5){
            log.error(">>>>>>>Exception: {}",e5);
        }

        return null;
    }
}
